home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / AHDI / AHDI603 / IDE.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  25.4 KB  |  960 lines

  1. ;+
  2. ; Edit History
  3. ;
  4. ; Sep-05-90    ml.    Created this for drives on the IDE bus.
  5. ;
  6. ; Mar-28-91    ml.    Do not use the IDE Sector Count Register 
  7. ;            to count down mulitiple sectors read or
  8. ;            write.  Some vendors (e.g. Conner and 
  9. ;            Seagate) seem to update this register 
  10. ;            too early, and every now and then, the
  11. ;            last sector of data would remain in the
  12. ;            internal sector buffer.  
  13. ;            
  14. ;            Code in ideread() and idewrite() are modified
  15. ;            not to use the IDE Sector Count Register.
  16. ;
  17. ; Aug-16-91    ml.    W4int() has been modified, in the case of
  18. ;            an error occurred, to return value in the 
  19. ;            Status register for driver code, and return 
  20. ;            value in the Error register for non-driver
  21. ;            code.
  22. ;
  23. ; Oct-10-91    ml.    Special-cased Conner drives for fmtunt() to
  24. ;            set drive to appropiate mode.  Added setmode().
  25. ;
  26. ; Oct-11-91    ml.    Special-cased Conner drives for read and write
  27. ;            to get current drive parameters.  Added gcparm().
  28. ;
  29. ; Mar-03-92    ml.    Added code to test if a drive exist on the IDE bus.
  30. ;
  31. ; Apr-14-92    ml.    For non-BLiTTER transfers, use move.w instead of
  32. ;            move.l, because it's too fast for the drives.
  33. ;
  34. ; Sep-04-92    Jh.    Disabled IRQ for Seagate Drive
  35. ;-
  36.  
  37. .include    "defs.h"
  38. .include    "sysvar.h"
  39. .include    "mfp.h"
  40. .include    "error.h"
  41. .include    "ide.h"
  42. .include    "blitter.h"
  43.  
  44. .extern    _useblit
  45.  
  46. ;+
  47. ; Wait for status to come back
  48. ;-
  49. w4int:    move.l    #D_WORST,d0    ; d0 = timeout limit
  50.     add.l    _hz_200,d0    ; d0 = expiration time
  51. .0:    btst.b    #5,GPIP        ; interrupt?
  52.     beq.s    .1        ; if so, out of the loop
  53.     cmp.l    _hz_200,d0    ; timeout?
  54.     bhi.s    .0        ; if not, wait some more
  55.     moveq    #$ff,d0        ; else, return timeout
  56.     bra.s    .3
  57. .1:    moveq    #0,d0        ; clear d0
  58.     move.b    IDESR,d0    ; d0.b = status returned
  59.     btst    #ERR,d0        ; any error?
  60.  
  61. .if    !DRIVER            ; for non-driver code
  62.     beq.s    .2        ; if no error, go on
  63.     move.b    IDEER,d0    ; else d0.b = error bits
  64.     bra.s    .3        ; return with error
  65.  
  66. .else                ; for driver code
  67.     bne.s    .3        ; if error, return
  68. .endif    ;!DRIVER
  69.  
  70. .2:    btst    #DRQ,d0        ; else DRQ?
  71.     bne.s    .3        ; if so, just return
  72.     moveq    #0,d0        ; else return OK
  73. .3:    rts            ; return status or error code
  74.  
  75.  
  76.  
  77. ;+
  78. ; ideread() - reads from 1 to 256 sectors as specified in the Task File,
  79. ;        beginning at the specified sector.
  80. ;        - sector count equal to 0 requests 256 sectors.
  81. ;
  82. ; ideread(nhd, nspt, sectnum, count, buf, pdev)
  83. ; WORD    nhd;        4(sp).w        ; # of data heads on pdev
  84. ; WORD    nspt;        6(sp).w        ; # of sectors per track
  85. ; LONG    sectnum;    8(sp).l        ; logical block address
  86. ; WORD    count;        $c(sp).w    ; # of sectors to read
  87. ; BYTE    *buf;        $e(sp).l    ; $f(sp)=high $10(sp)=mid $11(sp)=low
  88. ; WORD    pdev;        $12(sp).w    ; physical device number
  89. ;-
  90.     .globl    _ideread
  91. _ideread:
  92.     bsr    set_dhcs    ; set physical address
  93.     move.l    $e(sp),a0    ; a0 -> buffer to read into
  94.     move.b    $d(sp),IDESC    ; set sector count
  95.  
  96.     move.w    $c(sp),d1    ; d1.w = # of sectors to read
  97.     subq    #1,d1        ; dbra likes one less
  98.  
  99.     tst.b    _useblit    ; BLiTTER exists?
  100.     beq.s    .0        ; if not, don't use it
  101.     moveq    #0,d0        ; else it's a read
  102.     bsr    initblit    ; initialize the BLiTTER
  103.  
  104. .0:    move.b    #0,IDEDOR    ; enable interrupt
  105.     move.b    #READ,IDECR    ; set command code
  106. .1:    bsr    w4int        ; wait for interrupt
  107.     tst.w    d0        ; successful?
  108.     bmi.s    .2        ; if timed-out, return
  109.     btst    #DRQ,d0        ; DRQ?
  110.     beq.s    .2        ; if not, return
  111.                 ; else
  112.     bsr    readbuf        ; transfer data
  113.     dbra    d1,.1        ; go wait for next interrupt
  114.     moveq    #0,d0        ; everything is fine
  115. .2:    move.b    #2,IDEDOR    ; disable IRQ for SEAGATE 9/4/92
  116.     rts
  117.  
  118.  
  119. ;+
  120. ; idewrite() - writes from 1 to 256 sectors as specified in the Task File,
  121. ;        beginning at the specified sector.
  122. ;         - sector count equal to 0 requests 256 sectors.
  123. ;
  124. ; idewrite(nhd, nspt, sectnum, count, buf, pdev)
  125. ; WORD    nhd;        4(sp).w        ; # of data heads on pdev
  126. ; WORD    nspt;        6(sp).w        ; # of sectors per track
  127. ; LONG    sectnum;    8(sp).l        ; logical block address
  128. ; WORD    count;        $c(sp).w    ; # sectors to read
  129. ; BYTE    *buf;        $e(sp).l    ; $f(sp)=high $10(sp)=mid $11(sp)=low
  130. ; WORD    pdev;        $12(sp).w    ; physical device number
  131. ;-
  132.     .globl    _idewrite
  133. _idewrite:    
  134.     bsr    set_dhcs    ; set physical address
  135.     move.l    $e(sp),a0    ; a0 -> buffer to write from
  136.     move.b    $d(sp),IDESC    ; set sector count
  137.  
  138.     move.w    $c(sp),d1    ; d1.w = # of sectors to read
  139.     subq    #1,d1        ; dbra likes one less
  140.  
  141.     tst.b    _useblit    ; BLiTTER exists?
  142.     beq.s    .0        ; if not, don't use it
  143.     moveq    #1,d0        ; it's a write
  144.     bsr    initblit    ; initialize the BLiTTER
  145.  
  146. .0:    move.b    #0,IDEDOR    ; enable interrupt
  147.     move.b    #WRITE,IDECR    ; set command code
  148. .1:    btst.b    #DRQ,IDEASR    ; DRQ?
  149.     beq.s    .1        ; if not, wait longer
  150.  
  151. .2:    bsr    wrtbuf        ; transfer data
  152.     bsr    w4int        ; wait for interrupt
  153.     tst.w    d0        ; successful?
  154.     bmi.s    .3        ; if timed-out, return
  155.     btst    #DRQ,d0        ; DRQ?
  156.     beq.s    .3        ; if not, return
  157.     dbra    d1,.2        ; else go transfer data
  158.     moveq    #0,d0        ; everything is fine
  159. .3:    move.b    #2,IDEDOR    ; disable IRQ for SEAGATE 9/4/92
  160.     rts
  161.  
  162.  
  163. ;+
  164. ; set_dhcs() - convert a logical block address into a physical address.
  165. ;         - set drive #, head #, cylinder # and sector # in task file.
  166. ;
  167. ; Passed:
  168. ;    8(sp).w = nhd = # of data heads
  169. ;    $a(sp).w = nspt = # of sectors per track
  170. ;    $c(sp).l = logical block address
  171. ;    $16(sp).w = physical unit #
  172. ;-
  173. set_dhcs:
  174.     move.l    $c(sp),d1    ; d1.l = logical block address
  175.     move.w    8(sp),d2    ; d2.w = # of data heads
  176.     move.w    $a(sp),d0    ; d0.w = # of sectors per track
  177.     mulu    d0,d2        ; d2.l = # of sectors per cylinder
  178.                 ;      = # heads * # of sectors per track
  179.     divu.w    d2,d1        ; d1.w = cylinder #
  180.                 ;      = log block addr / #spc
  181.     move.b    d1,IDECL    ; set cylinder low
  182.     lsr.l    #8,d1        ; d1.b = cylinder high
  183.     move.b    d1,IDECH    ; set cylinder high
  184.     lsr.l    #8,d1        ; d1.l = sector # within the cyl
  185.     divu.w    d0,d1        ; d1.w = head #
  186.                 ;      = sector # within cyl / #spt
  187.     move.w    $16(sp),d0    ; d0.w = physical unit #
  188.     andi.b    #7,d0        ; mask off flags from physical unit #
  189.     lsl.b    #4,d0        ; shift unit # to place
  190.     or.b    d0,d1        ; or in drive #
  191. ;+
  192.     or.b    #$a0,d1
  193. ;-
  194.     move.b    d1,IDESDH    ; set drive and head #
  195.     swap    d1        ; d1.w = sector # (base 0)
  196.     addq.w    #1,d1        ;      = sector # + 1 (base 1)
  197.     move.b    d1,IDESN    ; set sector #
  198.     rts
  199.  
  200. ;+
  201. ; identify() - allows the Host to receive parameter information from
  202. ;           the drive.
  203. ;
  204. ; identify(pdev, buf)
  205. ; WORD    pdev;    4(sp).w        ; physical unit #
  206. ; BYTE    *buf;    6(sp).l        ; buffer to put data
  207. ;-
  208.     .globl    _identify
  209. _identify:
  210.     move.w    4(sp),d0    ; d0 = physical unit #
  211.     andi.b    #7,d0        ; mask off flags (if any)
  212.     lsl.b    #4,d0        ; shift unit # to place
  213. ;+
  214.     or.b    #$a0,d0
  215. ;-
  216.     move.b    d0,IDESDH    ; set drive #
  217.     move.l    6(sp),a0    ; a0 -> buffer
  218.  
  219.     tst.b    _useblit    ; BLiTTER exists?
  220.     beq.s    .0        ; if not, no need to init it
  221.     moveq    #0,d0        ; it's a read
  222.     bsr    initblit    ; initialize the BLiTTER
  223.  
  224. .0:    move.b    #0,IDEDOR    ; enable interrupt
  225.     move.b    #IDENTIFY,IDECR    ; set command code
  226.     bsr    w4int        ; wait for interrupt
  227.     tst.w    d0        ; successful?
  228.     bmi.s    .1        ; if timed-out, return
  229.     btst    #DRQ,d0        ; DRQ?
  230.     beq.s    .1        ; if not, return with error
  231.  
  232.     bsr    readbuf        ; read data
  233.     moveq    #0,d0        ; everything is fine
  234. .1:    move.b    #2,IDEDOR    ; disable IRQ for SEAGATE 9/4/92
  235.     rts 
  236.  
  237.  
  238. ;+
  239. ; awto() - set drive to Active mode with timeout counter (in 5s increments)
  240. ;
  241. ; awto(pdev, timeout)
  242. ; WORD    pdev;        4(sp).w        ; physical unit #
  243. ; WORD    timeout;    6(sp).w
  244. ;-
  245.     .globl    _awto
  246. _awto:    
  247.     move.w    4(sp),d0    ; d0 = physical unit #
  248.     andi.b    #7,d0        ; mask off flags (if any)
  249.     lsl.b    #4,d0        ; shift unit # to place
  250. ;+
  251.     or.b    #$a0,d0
  252. ;-
  253.     move.b    d0,IDESDH    ; set drive #
  254.     move.b    7(sp),IDESC    ; set timeout counter
  255.     move.b    #AWTO,IDECR    ; set command code
  256.     bra    w4int        ; go wait for interrupt
  257.  
  258.  
  259. ;+
  260. ; readbuf() - reads 512 bytes (128 longs) of data from the sector
  261. ;        buffer.
  262. ;
  263. ; Comments:
  264. ;    A tower of 8 move.l is used to try to speed up the transfer.
  265. ;
  266. ; Passed:
  267. ;    a0.l = buffer to store data read from sector buffer
  268. ;
  269. ;    if BLiTTER code
  270. ;    a1.l = base address of BLiTTER
  271. ;-
  272. readbuf:
  273.     tst.b    _useblit    ; BLiTTER exists?
  274.     beq.s    .0        ; if not, do programmed IO
  275.     move.w    #1,YCNT(a1)    ; one destination line
  276.     move.b    #$80,BUSY(a1)    ; start the BLiTTER
  277.     bsr    restart
  278.     addq.l    #2,DESTADDR(a1)    ; advance to next word of destination
  279.     rts
  280.                 ; Programmed IO
  281. .0:    moveq    #31,d0        ; d0 = (# of words to read / 8) - 1
  282.     lea    IDEDR,a1    ; a1 -> data bus
  283. .1:    move.w    (a1),(a0)+    ; read data from bus
  284.     move.w    (a1),(a0)+    ; read data from bus
  285.     move.w    (a1),(a0)+    ; read data from bus
  286.     move.w    (a1),(a0)+    ; read data from bus
  287.     move.w    (a1),(a0)+    ; read data from bus
  288.     move.w    (a1),(a0)+    ; read data from bus
  289.     move.w    (a1),(a0)+    ; read data from bus
  290.     move.w    (a1),(a0)+    ; read data from bus
  291.     dbra    d0,.1        ; repeat until all done
  292.     rts
  293.  
  294.  
  295. ;+
  296. ; wrtbuf() - writes 512 bytes (128 longs) of data to sector buffer.
  297. ;
  298. ; Passed:
  299. ;    a0.l = buffer with data to write to sector buffer
  300. ;-
  301. wrtbuf:
  302.     tst.b    _useblit    ; BLiTTER exists?
  303.     beq.s    .0        ; if not, do programmed IO
  304.     move.w    #1,YCNT(a1)    ; one destination line
  305.     move.b    #$80,BUSY(a1)    ; start the BLiTTER
  306.     bsr    restart
  307.     addq.l    #2,SRCADDR(a1)    ; advance to next word of source
  308.     rts
  309.                 ; Programmed IO
  310. .0:    moveq    #31,d0        ; d0 = (# longs to write / 8) - 1
  311.     lea    IDEDR,a1    ; a1 -> data bus
  312. .1:    move.w    (a0)+,(a1)    ; write data to bus
  313.     move.w    (a0)+,(a1)    ; write data to bus
  314.     move.w    (a0)+,(a1)    ; write data to bus
  315.     move.w    (a0)+,(a1)    ; write data to bus
  316.     move.w    (a0)+,(a1)    ; write data to bus
  317.     move.w    (a0)+,(a1)    ; write data to bus
  318.     move.w    (a0)+,(a1)    ; write data to bus
  319.     move.w    (a0)+,(a1)    ; write data to bus
  320.     dbra    d0,.1        ;  repeat until all done
  321.     rts
  322.  
  323.  
  324. ;+
  325. ; drvxst() - test if an IDE drive exists
  326. ;
  327. ; Returns:  0 - if drive does not exist
  328. ;        1 - if drive exists
  329. ;-
  330.     .globl    _drvxst
  331. _drvxst:
  332.     move.w    #$5a5a,IDEDR
  333.     move.w    IDEDR,d0
  334.     cmpi.w    #$5a5a,d0
  335.     bne.s    .0
  336.     moveq    #1,d0        ; else, drive exists
  337.     rts
  338. .0:    moveq    #0,d0        ; drive does not exist
  339.     rts
  340.  
  341.  
  342. ;+
  343. ; initblit() - initialize the BLiTTER chip for 512 bytes I/O transfer
  344. ;
  345. ; Passed:
  346. ;    a0.l = destination address if read; source address if write
  347. ;    d0.w = flag to tell whether it's a read or a write
  348. ;-
  349. initblit:
  350.     lea    bBLiTTER,a1        ; a1 -> BLiTTER register map
  351.     tst.b    d0            ; read or write?
  352.     bne.s    ib0            ; (write)
  353.     move.l    #IDEDR,SRCADDR(a1)    ; source addr = IDE data register
  354.     move.l    a0,DESTADDR(a1)        ; destination addr = given buffer
  355.     move.w    #2,DESTXINC(a1)        ; words read
  356.     moveq    #0,d0
  357.     move.w    d0,SRCXINC(a1)        ; never increment source X
  358.     bra.s    ib1
  359.                     ; initialize BLiTTER to write to disk
  360. ib0:    move.l    a0,SRCADDR(a1)        ; source addr = write buffer
  361.     move.l    #IDEDR,DESTADDR(a1)    ; destination addr = IDE data reg
  362.     move.w    #2,SRCXINC(a1)        ; words write
  363.     moveq    #0,d0
  364.     move.w    d0,DESTXINC(a1)        ; never increment destination X
  365.  
  366. ib1:    move.w    d0,SRCYINC(a1)        ; never increment source Y
  367.     move.w    d0,DESTYINC(a1)        ; never increment destination Y
  368.     move.b    d0,SKEW(a1)        ; no skew
  369.     moveq    #$ff,d0
  370.     move.l    d0,ENDMASK1(a1)        ; change all bits at destination
  371.     move.w    d0,ENDMASK3(a1)        ; change all bits at destination
  372.     move.w    #$203,HOP(a1)        ; set HOP and OP to source
  373.     move.w    #256,XCNT(a1)        ; num of words to transfer
  374.     rts
  375.  
  376.  
  377. ;+
  378. ; restart() - restart the BLiTTER
  379. ;
  380. ; Passed:
  381. ;    a1.l = base address of BLiTTER
  382. ;-
  383. restart:
  384.     nop
  385.     tas    BUSY(a1)    ; restart BLiTTER and test if busy
  386.     bmi.s    restart        ; quit if not busy
  387.     rts
  388.  
  389.  
  390. ;+
  391. ; gcparm() - get current drive parameters
  392. ;
  393. ; gcparm(buf)
  394. ; char    *buf;    $4(sp).l    /* -> data returned by identify() */
  395. ;
  396. ; Returns:
  397. ;    d0.w = # of default cylinders
  398. ;    d1.w = # of default heads
  399. ;    d2.w = # of default sectors per track
  400. ;-
  401.     .globl    _gcparm
  402. _gcparm:
  403.     move.l    4(sp),a0    ; a0 -> data buffer
  404.     add.l    #CONMDL,a0    ; a0 -> where Conner model number is
  405.     move.l    a0,-(sp)
  406.     pea    cp2024
  407.     move.w    #6,-(sp)
  408.     bsr    strcmp        ; compare model# with "CP2024"
  409.     adda    #10,sp        ; clean up stack
  410.     tst.w    d0        ; is unit the CP2024 (Kato 20Mb)?
  411.     bne.s    gcp0        ; if not, handle the normal way
  412.                 ; else return default values of CP2024
  413.     move.w    #CP20NCYL,d0    ; d0.w = # of cylinders
  414.     move.w    #CP20NHEAD,d1    ; d1.w = # of heads
  415.     move.w    #CP20NSPT,d2    ; d2.w = # of spt
  416.     bra.s    gcpend
  417.  
  418. gcp0:    move.l    4(sp),a0
  419.     move.w    NCYL(a0),d0    ; d0.w = # of cylinders
  420.     move.w    NHEAD(a0),d1    ; d1.w = # of heads
  421.     move.w    NSPT(a0),d2    ; d2.w = # of sectors per track
  422.  
  423. gcpend:    rts
  424.  
  425.  
  426.  
  427. conner:    dc.b    "Conner",0
  428. .even
  429. cp2024:    dc.b    "CP2024",0
  430. .even
  431.  
  432.  
  433. ;+
  434. ; strcmp() - compare two strings
  435. ;
  436. ; Passed:
  437. ;    4(sp).w  = n (# of bytes to compare)
  438. ;    6(sp).l  = address of first string
  439. ;    10(sp).l = address of second string
  440. ;
  441. ; Returns:
  442. ;    d0.w = 0    if first n bytes of the 2 strings are the same
  443. ;         = non-0    otherwise
  444. ;-
  445. strcmp:    movem.l    d1/a0-a1,-(sp)    ; save registers d1, a0 and a1
  446.     move.w    16(sp),d1    ; d1 = byte count
  447.     subq.w    #1,d1        ; dbra likes one less
  448.     move.l    18(sp),a0    ; a0 -> string 1
  449.     move.l    22(sp),a1    ; a1 -> string 2
  450.     moveq    #1,d0        ; assume strings are not the same
  451. .0:    cmpm.b    (a0)+,(a1)+    ; characters the same?
  452.     bne.s    .1        ; if not, return
  453.     dbra    d1,.0        ; else compare next character
  454.     moveq    #0,d0        ; the strings are the same
  455. .1:    movem.l    (sp)+,d1/a0-a1    ; restore registers d1, a0 and a1
  456.     rts
  457.  
  458.  
  459. .if    !DRIVER
  460.  
  461. ;+
  462. ; recal() - moves the R/W heads from anywhere on the disk to cylinder 0.
  463. ;
  464. ; recal(pdev)
  465. ; WORD    pdev;    $4(sp).w
  466. ;-
  467.     .globl    _recal
  468. _recal:    move.w    4(sp),d0    ; d0 = physical unit #
  469.     andi.b    #7,d0        ; mask off flags (if any)
  470.     lsl.b    #4,d0        ; shift unit # to place
  471. ;+
  472.     or.b    #$a0,d0
  473. ;-
  474.     move.b    d0,IDESDH    ; write drive #
  475.     move.b    #0,IDEDOR    ; enable interrupt
  476.     move.b    #RECAL,IDECR    ; write command code
  477.     bsr    w4int        ; go wait for interrupt
  478.     move.b    #2,IDEDOR    ; disable IRQ for SEAGATE 9/4/92
  479.     rts
  480. ;+
  481. ; verify() - functions similarly to read() except that no data is
  482. ;         transferred to the host.
  483. ;-
  484.     .globl    _verify
  485. _verify:
  486.     move.w    $e(sp),d0    ; d0.w = physical unit #
  487.     move.l    4(sp),d1    ; d1.l = starting logical sector #
  488.     bsr    set_dhcs    ; set drive#, head#, cylinder# and sector#
  489.     move.l    $a(sp),a0    ; a0 -> buffer to write from
  490.     move.b    9(sp),IDESC    ; set sector count
  491.     move.b    #0,IDEDOR    ; enable interrupt
  492.     move.b    #VERIFY,IDECR    ; set command code
  493. .0:    bsr    w4int        ; wait for interrupt
  494.     bne.s    .1        ; if has error, return
  495.     tst.b    IDESC        ; more to verify?
  496.     bne.s    .0        ; if so, continue
  497.     moveq    #0,d0        ; everything's fine
  498. .1:    move.b    #2,IDEDOR    ; disable IRQ for SEAGATE 9/4/92
  499.     rts
  500.  
  501.  
  502. ;+
  503. ; fmtunt() - formats a unit
  504. ;       - always formats sectors as good ones.
  505. ;       - interleave 1:1.
  506. ;
  507. ; fmtunt(pdev)
  508. ; WORD    pdev;    4(sp).w
  509. ;-
  510.     .globl    _fmtunt
  511. _fmtunt:
  512.     movem.l    d3-d4,-(sp)    ; save d3 and d4
  513.     move.w    $c(sp),-(sp)    ; set selected unit to the appropiate
  514.     bsr    setmode        ;  mode and get drive parameters in d1-d3
  515.     addq    #2,sp        ; clean up stack
  516.     tst.w    d0        ; setmode() ok?
  517.     bne    .5        ; if not, return
  518.                 ; else fill format data
  519.     bsr    clrsbuf        ; clear scratch buffer
  520.     moveq    #1,d0        ; d0 = sector # (starts with sector 1)
  521.     lea    sbuf,a1        ; a1 -> _identify() data buffer
  522. .0:    move.b    d0,(a1)+    ; set sector #
  523.     clr.b    (a1)+        ; format sector good
  524.     addq.b    #1,d0        ; next sector #
  525.     cmp.b    d0,d3        ; all sector # set?
  526.     bcc.s    .0        ; if not, continue
  527.                 ; format unit
  528.     move.w    $c(sp),d4    ; d4.w = physical unit #
  529.     andi.b    #7,d4        ; mask off flags (if any)
  530.     lsl.b    #4,d4        ; shift physical unit # into place
  531. ;+
  532.     or.b    #$a0,d4
  533. ;-
  534.     move.b    d4,IDESDH    ; set physical unit #
  535.     subq.w    #1,d1        ; dbra likes one less
  536.     subq.w    #1,d2        ; dbra likes one less
  537.     move.w    d2,d4        ; d4 = # heads - 1
  538.     lea    sbuf,a0        ; a0 -> format data
  539. .1:    move.w    d4,d2        ; reinitialize head number for next cylinder
  540. .2:    movem.l    d1-d4/a0,-(sp)    ; save cylinder and head count
  541.     move.b    d3,IDESC    ; sector count = # sectors per track
  542.     bsr    _fmttrk        ; format track of current cylinder and head
  543.     bne.s    .4        ; if fail, return
  544. .3:    movem.l    (sp)+,d1-d4/a0    ; restore cylinder and head count
  545.     dbra    d2,.2        ; for all heads
  546.     dbra    d1,.1        ; for all cylinders
  547.     moveq    #0,d0        ; everything's fine
  548.     bra.s    .5        ; and return
  549. .4:    adda.l    #20,sp        ; else clean up stack
  550. .5:    movem.l    (sp)+,d3-d4    ; restore d3 and d4
  551.     rts
  552.  
  553.  
  554.  
  555. ;+
  556. ; setmode() - set the unit to its default mode and return the default
  557. ;        drive parameters.
  558. ;
  559. ; setmode(pdev)
  560. ; WORD    pdev;    $4(sp).w
  561. ;
  562. ; Returns:
  563. ;    d0.w = 0    if successful
  564. ;         = non-0    if failed
  565. ;    d1.w = # of default cylinders
  566. ;    d2.w = # of default heads
  567. ;    d3.w = # of default sectors per track
  568. ;
  569. ; Comments:
  570. ;    This routine distinguishes the Conner drives from other vendors'
  571. ; because Conner saves their default values in a reserved area. (Sigh)
  572. ; Furthermore, since the default parameters are not stored on the Conner 
  573. ; CP2024 (20Mb) drives at all, they are being hardwired into the code. 
  574. ; (I know, it's terrible!)
  575. ;-
  576. setmode:
  577.     pea    sbuf        ; scratch buffer
  578.     move.w    8(sp),-(sp)    ; physical unit #
  579.     bsr    _identify    ; identify(pdev, buf)
  580.     addq.w    #6,sp        ; clean up stack
  581.     tst.w    d0        ; successful?
  582.     bne    smend        ; if not, return
  583.                 ; else 
  584.     lea    sbuf,a1        ; a1 -> data buffer
  585.     move.l    #sbuf+MDLNUM,-(sp)
  586.     pea    conner
  587.     move.w    #6,-(sp)
  588.     bsr    strcmp        ; compare model# with "Conner"
  589.     adda    #10,sp        ; clean up stack
  590.     tst.w    d0        ; is unit a Conner drive?
  591.     bne.s    other        ; if not, handle the normal way
  592.                 ; else
  593.     move.l    #sbuf+CONMDL,-(sp)
  594.     pea    cp2024
  595.     move.w    #6,-(sp)
  596.     bsr    strcmp        ; compare model# with "CP2024"
  597.     adda    #10,sp        ; clean up stack
  598.     tst.w    d0        ; is unit the CP2024 (Kato 20Mb)?
  599.     bne.s    nkato        ; if not, parms at reserved area
  600.                 ; else return default values of CP2024
  601.     move.w    #CP20NCYL,d1    ; d1.w = # of cylinders
  602.     move.w    #CP20NHEAD,d2    ; d2.w = # of heads
  603.     move.w    #CP20NSPT,d3    ; d3.w = # of spt
  604.     bra.s    smend        ; no need to init parm, just return
  605.  
  606.                 ; for other Conner drives
  607. nkato:    move.w    CPNCYL(a1),d1    ; get parameters at Conner
  608.     moveq    #0,d2        ;   reserved location
  609.     move.b    CPNHEAD(a1),d2
  610.     moveq    #0,d3
  611.     move.b    CPNSPT(a1),d3
  612.     bra.s    sminit        ; go do initparm
  613.  
  614. other:    move.w    NCYL(a1),d1    ; d1.w = # of cylinders
  615.     move.w    NHEAD(a1),d2    ; d2.w = # of heads
  616.     move.w    NSPT(a1),d3    ; d3.w = # of sectors per track
  617.  
  618. sminit:    movem.l    d1-d3,-(sp)    ; save drive parameters
  619.     move.w    d3,-(sp)    ; sectors per track
  620.     move.w    d2,-(sp)    ; # of heads
  621.     move.w    20(sp),-(sp)    ; physical unit #
  622.     bsr    _initparm    ; set drive to default mode
  623.     addq.w    #6,sp        ; clean up stack
  624.     movem.l    (sp)+,d1-d3    ; restore drive parameters
  625.  
  626. smend:    rts
  627.  
  628.  
  629. ;+
  630. ; clrsbuf() - clear the scratch buffer
  631. ;-
  632. clrsbuf:
  633.     movem.l    d0/a0,-(sp)    ; save d0 and a0
  634.     lea    sbuf,a0        ; a0 -> scratch buffer
  635.     move.w    #127,d0        ; d0 = counter
  636. .0:    clr.l    (a0)+        ; clear 4 bytes
  637.     dbra    d0,.0        ; repeat until done
  638.     movem.l    (sp)+,d0/a0    ; restore d0 and a0
  639.     rts
  640.  
  641.  
  642. ;+
  643. ; fmttrk() - formats a track with format data provided.
  644. ;
  645. ; Passed:
  646. ;    d1.w = cylinder #
  647. ;    d2.w = head #
  648. ;    a0.l -> format data
  649. ;-
  650.     .globl    _fmttrk
  651. _fmttrk:
  652.     andi.b    #$f0,IDESDH    ; erase previous head #
  653.     or.b    d2,IDESDH    ; set new head #
  654.     move.b    d1,IDECL    ; set cylinder low
  655.     lsr.w    #8,d1        ; d0.b = cylinder high
  656.     move.b    d1,IDECH    ; set cylinder high
  657.     move.b    #0,IDEDOR    ; enable interrupt
  658.  
  659.     tst.b    _useblit    ; use BLiTTER?
  660.     beq.s    .0        ; if not, no need to init it
  661.     moveq    #1,d0        ; write through BLiTTER
  662.     bsr    initblit    ; initialize the BLiTTER
  663.  
  664. .0:    move.b    #FMTTRK,IDECR    ; set command code
  665. .1:    btst.b    #DRQ,IDEASR    ; DRQ?
  666.     beq.s    .1        ; if not, wait longer
  667.  
  668.     bsr    wrtbuf        ; write format data to sector buffer
  669.     bsr    w4int
  670.     move.b    #2,IDEDOR    ; disable IRQ for SEAGATE 9/4/92
  671.     rts
  672.  
  673. ;+
  674. ; seek() - initiates a seek to the track and selects the head 
  675. ;       specified in the Task File.
  676. ;
  677. ; seek(pdev, head, cyl)
  678. ; WORD    pdev;    $4(sp).w
  679. ; WORD    head;    $6(sp).w
  680. ; WORD    cyl;    $8(sp).w
  681. ;-
  682.     .globl    _seek
  683. _seek:    move.w    4(sp),d0    ; d0 = physical unit #
  684.     andi.b    #7,d0        ; mask off flags
  685.     lsl.b    #4,d0        ; shift unit # to place
  686.     or.b    7(sp),d0    ; b4 of d0 = drive #; b3-b0 of d0 = head #;
  687. ;+
  688.     or.b    #$a0,d0
  689. ;-
  690.     move.b    d0,IDESDH    ; set drive and head #
  691.     move.b    #0,IDEDOR    ; enable interrupt
  692.     move.b    9(sp),IDECL    ; set cylinder low
  693.     move.b    8(sp),IDECH    ; set cylinder high
  694.     move.b    #SEEK,IDECR    ; set command code
  695.     bsr    w4int        ; go wait for interrupt
  696.     move.b    #2,IDEDOR    ; disable IRQ for SEAGATE 9/4/92
  697.     rts
  698.  
  699. ;+
  700. ; diag() - performs the internal diagnostic tests implemented by 
  701. ;       the drive.
  702. ;-
  703.     .globl    _diag
  704. _diag:    move.b    #0,IDEDOR    ; enable interrupt
  705.     move.b    #DIAG,IDECR    ; set command code
  706.     bsr    w4int
  707.     move.b    #2,IDEDOR    ; disable IRQ for SEAGATE 9/4/92
  708.     rts
  709.  
  710.  
  711. ;+
  712. ; initparm() - enables the host to set the head switch and cylinder
  713. ;           increment points for multiple sector operations.
  714. ;
  715. ; initparm(pdev, head, spt)
  716. ; WORD     pdev;    4(sp).w
  717. ; WORD    head;    6(sp).w
  718. ; WORD    spt;    8(sp).w
  719. ;-
  720.     .globl    _initparm
  721. _initparm:
  722.     move.w    4(sp),d0    ; d0 = physical unit #
  723.     andi.b    #7,d0        ; mask off flags
  724.     lsl.w    #4,d0        ; shift it into place
  725. ;+
  726.     or.b    #$a0,d0
  727. ;-
  728.     move.b    d0,IDESDH    ; set physical unit #
  729.     move.w    6(sp),d0    ; d0 = # of heads
  730.     subq.b    #1,d0        ; maximum head #
  731.     or.b    d0,IDESDH    ; set head #
  732.     move.b    9(sp),IDESC    ; set sectors per track
  733.     move.b    #0,IDEDOR    ; enable interrupt
  734.     move.b    #INITPARM,IDECR    ; set command code
  735.     bsr    w4int        ; go wait for interrupt
  736.     move.b    #2,IDEDOR    ; disable IRQ for SEAGATE 9/4/92
  737.     rts
  738.  
  739.  
  740. ;+
  741. ; rsbuf() - allows the Host to read the current contents of the
  742. ;        drive's sector buffer.
  743. ;
  744. ; rsbuf(pdev, buf)
  745. ; WORD    pdev;    4(sp).w
  746. ; BYTE    *buf;    6(sp).l
  747. ;-
  748.     .globl    _rsbuf
  749. _rsbuf:    move.w    4(sp),d0    ; d0 = physical unit #
  750.     andi.b    #7,d0        ; mask off flags (if any)
  751.     lsl.w    #4,d0        ; shift it into place
  752. ;+
  753.     or.b    #$a0,d0
  754. ;-
  755.     move.b    d0,IDESDH    ; set physical unit #
  756.     move.l    6(sp),a0    ; a0 -> buffer
  757.     move.w    #256,d1
  758.  
  759.     tst.b    _useblit    ; BLiTTER exists?
  760.     beq.s    .0        ; if not, don't use it
  761.     moveq    #0,d0        ; it's a read
  762.     bsr    initblit    ; initialize the BLiTTER
  763.  
  764. .0:    move.b    #0,IDEDOR    ; enable interrupt
  765.     move.b    #RSBUF,IDECR    ; set command code
  766.     bsr    w4int        ; go wait for interrupt
  767.     tst.w    d0        ; successful?
  768.     bmi.s    .1        ; if timed-out, return
  769.     btst    #DRQ,d0        ; DRQ?
  770.     beq.s    .1        ; if not, return with error
  771.  
  772.     bsr    readbuf        ; read data
  773.     moveq    #0,d0        ; everything is fine
  774. .1:    move.b    #2,IDEDOR    ; disable IRQ for SEAGATE 9/4/92
  775.     rts 
  776.  
  777.  
  778. ;+
  779. ; wsbuf() - allows the Host to overwrite the contents of the drive's
  780. ;        sector buffer.
  781. ;
  782. ; wsbuf(pdev, buf)
  783. ; WORD    pdev;    4(sp).w
  784. ; BYTE    *buf;    6(sp).l
  785. ;-
  786.     .globl    _wsbuf
  787. _wsbuf:    move.w    4(sp),d0    ; d0 = physical unit #
  788.     andi.b    #7,d0        ; mask off flags (if any)
  789.     lsl.w    #4,d0        ; shift it into place
  790. ;+
  791.     or.b    #$a0,d0
  792. ;-
  793.      move.b    d0,IDESDH    ; set physical unit #
  794.     move.l    6(sp),a0    ; a0 -> buffer
  795.     move.w    #256,d0        ; d0 = word count
  796.  
  797.     tst.b    _useblit    ; BLiTTER exists?
  798.     beq.s    .0        ; if not, don't use it
  799.     moveq    #0,d0        ; it's a read
  800.     bsr    initblit    ; initialize the BLiTTER
  801.  
  802. .0:    move.b    #WSBUF,IDECR    ; set command code
  803. .1:    btst    #DRQ,IDESR    ; DRQ?
  804.     beq.s    .1        ; if not, wait some more
  805.  
  806.     bsr    wrtbuf        ; write data
  807.     moveq    #0,d0        ; everything is fine
  808.     rts
  809.  
  810.  
  811. ;+
  812. ; standby() - set drive to Standby mode
  813. ;
  814. ; standby(pdev)
  815. ; WORD    pdev;    4(sp).w        ; physical unit #
  816. ;-
  817.     .globl    _standby
  818. _standby:
  819.     move.w    4(sp),d0    ; d0 = physical unit #
  820.     andi.b    #7,d0        ; mask off flags (if any)
  821.     lsl.b    #4,d0        ; shift unit # to place
  822. ;+
  823.     or.b    #$a0,d0
  824. ;-
  825.     move.b    d0,IDESDH    ; set drive #
  826.     move.b    #STANDBY,IDECR    ; set command code
  827.     bra    w4int        ; go wait for interrupt
  828.  
  829.  
  830. ;+
  831. ; active() - set drive to Active mode
  832. ;
  833. ; active(pdev)
  834. ; WORD    pdev;    4(sp).w        ; physical unit #
  835. ;-
  836.     .globl    _active
  837. _active:
  838.     move.w    4(sp),d0    ; d0 = physical unit #
  839.     andi.b    #7,d0        ; mask off flags (if any)
  840.     lsl.b    #4,d0        ; shift unit # to place
  841. ;+
  842.     or.b    #$a0,d0
  843. ;-
  844.     move.b    d0,IDESDH    ; set drive #
  845.     move.b    #ACTIVE,IDECR    ; set command code
  846.     bra    w4int        ; go wait for interrupt
  847.  
  848.  
  849. ;+
  850. ; sbwto() - set drive to Standby mode with timeout counter (in 5s increments)
  851. ;
  852. ; sbwto(pdev, timeout)
  853. ; WORD    pdev;        4(sp).w        ; physical unit #
  854. ; WORD    timeout;    6(sp).w
  855. ;-
  856.     .globl    _sbwto
  857. _sbwto:    
  858.     move.w    4(sp),d0    ; d0 = physical unit #
  859.     andi.b    #7,d0        ; mask off flags (if any)
  860.     lsl.b    #4,d0        ; shift unit # to place
  861. ;+
  862.     or.b    #$a0,d0
  863. ;-
  864.     move.b    d0,IDESDH    ; set drive #
  865.     move.b    7(sp),IDESC    ; set timeout counter
  866.     move.b    #SBWTO,IDECR    ; set command code
  867.     bra    w4int        ; go wait for interrupt
  868.  
  869.  
  870. ;+
  871. ; ssc() - set sector count wrt current mode of drive
  872. ;
  873. ; ssc(pdev)
  874. ; WORD    pdev;    4(sp).w        ; physical unit #
  875. ;-
  876.     .globl    _ssc
  877. _ssc:    
  878.     move.w    4(sp),d0    ; d0 = physical unit #
  879.     andi.b    #7,d0        ; mask off flags (if any)
  880.     lsl.b    #4,d0        ; shift unit # to place
  881. ;+
  882.     or.b    #$a0,d0
  883. ;-
  884.     move.b    d0,IDESDH    ; set drive #
  885.     move.b    #SSC,IDECR    ; set command code
  886.     bra    w4int        ; go wait for interrupt
  887.  
  888.  
  889. ;+
  890. ; sbres() - set drive to Standby mode.
  891. ;      - drive will not wake up until reset is sent to drive
  892. ;
  893. ; sbres(pdev)
  894. ; WORD    pdev;    4(sp).w        ; physical unit #
  895. ;-
  896.     .globl    _sbres
  897. _sbres:    
  898.     move.w    4(sp),d0    ; d0 = physical unit #
  899.     andi.b    #7,d0        ; mask off flags (if any)
  900.     lsl.b    #4,d0        ; shift unit # to place
  901. ;+
  902.     or.b    #$a0,d0
  903. ;-
  904.     move.b    d0,IDESDH    ; set drive #
  905.     move.b    #SBRES,IDECR    ; set command code
  906.     bra    w4int        ; go wait for interrupt
  907.  
  908.  
  909. ;+
  910. ; slave() - test if the slave drive exists
  911. ;
  912. ; Returns: 0 - if slave does not exist
  913. ;       1 - if slave exists
  914. ;-
  915.     .globl    _slave
  916. _slave:    moveq    #0,d0        ; assume slave does NOT exist
  917.     bset.b    #4,IDESDH    ; set drive bit to 1 (slave)
  918.     btst.b    #DRDY,IDESR    ; is slave ready?
  919.     beq.s    .0        ; if not, no slave
  920.     moveq    #1,d0        ; else, slave exists
  921. .0:    rts
  922.  
  923.  
  924. ;+
  925. ; _iderdy() - test if the IDE drive is ready
  926. ;
  927. ; Passed:
  928. ;    d0.b = IDE drive unit #
  929. ;
  930. ; Returns: 0 - if drive is NOT ready
  931. ;       1 - if drive is ready
  932. ;-
  933.     .globl    _iderdy
  934. _iderdy:
  935.     andi.b    #7,d0        ; mask off flags (if any)
  936.     lsl.b    #4,d0        ; shift unit # to place
  937. ;+
  938.     or.b    #$a0,d0
  939. ;-
  940.     move.b    d0,IDESDH    ; set drive #
  941.     move.b    #$50,d1        ; ready status
  942.     move.l    #IDERDY,d0    ; set up timer
  943.     add.l    _hz_200,d0
  944. ir0:    cmp.b    IDEASR,d1    ; is drive ready and not busy?
  945.     beq.b    ir1        ; if so, return with drive ready
  946.     cmp.l    _hz_200,d0    ; time-out yet?
  947.     bcc.b    ir0        ; if not, wait longer
  948.     moveq    #0,d0        ; else return drive NOT ready
  949.     rts
  950. ir1:    moveq    #1,d0        ; else, drive is ready
  951.     rts
  952.  
  953.  
  954. .data
  955. sbuf:    dcb.b    512,0        ; scratch buffer
  956.  
  957. .endif    ;!DRIVER
  958.  
  959.  
  960.